package com.autonavi.yunda.yunji.controller.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

@Slf4j
@Aspect
@Component
public class DecodeAspect {
    @Before("@annotation(DecodeExtraData)")
    public void beforeAdvice(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            decodeField(arg, "extraData");
            decodeField(arg, "engineData");
        }
    }

    void decodeField(Object arg, String fieldName) {
        Field field = findFieldInClassHierarchy(arg.getClass(), fieldName);
        if (field != null) {
            boolean accessible = field.isAccessible();
            try {
                field.setAccessible(true);
                Object value = field.get(arg);
                if (value instanceof String) {
                    String encodedExtraData = (String) value;
                    if (!encodedExtraData.isEmpty()) {
                        String decodedData = new String(Base64.getDecoder().decode(encodedExtraData.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
                        field.set(arg, decodedData);
                    }
                }
            } catch (IllegalArgumentException e) {

            } catch (Exception e) {
                log.error("decode " + fieldName + " error " + e.getMessage(), e);
            } finally {
                field.setAccessible(accessible);
            }
        }
    }


    private Field findFieldInClassHierarchy(Class<?> clazz, String fieldName) {
        Class<?> current = clazz;
        while (current != null) {
            try {
                return current.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                current = current.getSuperclass();
            }
        }
        return null;
    }
}
